package com.tbit.uqbike.service.base.impl;

import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.business.CalibrateUtils;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.service.base.BatteryModelDetailService;
import com.tbit.uqbike.service.base.CalibrateService;
import com.tbit.uqbike.service.base.HistoryService;
import com.tbit.uqbike.service.rpcservice.PurviewService;
import com.tbit.uqbike.webmanager.dao.core.MachineBorrowDao;
import com.tbit.uqbike.webmanager.dao.core.MachineDao;
import com.tbit.uqbike.webmanager.dao.core.RideLogDao;
import com.tbit.uqbike.webmanager.dao.history.HistoryDao;
import com.tbit.utils.DateTimeUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;

@Service("historyService")
public class HistoryServiceImpl implements HistoryService {
    @Autowired
    private HistoryDao historyDao;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private RideLogDao rideLogDao;
    @Autowired
    private MachineDao machineMapper;
    @Autowired
    private MachineBorrowDao machineBorrowDao;
    @Autowired
    private PurviewService purviewService;
    @Autowired
    private BatteryModelDetailService batteryModelDetailService;

    @Override
    public List<TerPosition> getByMachineNOAndTime(Integer mapType, String machineNO, Long startTime, Long endTime,Integer machineId) {
        /*Map<String, Object> params = new HashMap<String, Object>();
        params.put("machineNO", machineNO);
        params.put("startTime", new Date(startTime));
        params.put("endTime", new Date(endTime));*/
        //获取查询的时间分段参数
        String start = DateTimeUtil.DateTimeToString(new Date(startTime));
        String end = DateTimeUtil.DateTimeToString(new Date(endTime));
        List<Map<String, Object>> searchParams = this.getSearchParams(machineNO, start, end,"machineNO",true);
        List<TerPosition> historyList = new ArrayList<>();
        for (Map<String, Object> param : searchParams) {
            List<TerPosition> history = historyDao.getByMachineNOAndTime(param);
            if (CollectionUtils.isNotEmpty(history)) {
                CalibrateUtils.calibrateObjects(calibrateService, history, mapType);
                historyList.addAll(history);
            }
        }
        //获取车辆各个轨迹点的电量
        this.getMachineSoc(historyList,machineId);

        return historyList;
    }

    private Machine purviewCheckUserCode(LoginInfo li, String userCode) {
        Machine machine = machineMapper.selectByUserCode(userCode);
        if (null == machine) {
            throw new BaseException(SystemCodeEnum.MACHINE_NOT_EXIST);
        }
        if (!purviewService.purviewCheck(li.id, machine)) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
        return machine;
    }

    @Override
    public List<TerPosition> getByUserCodeAndTime(LoginInfo loginInfo, Integer mapType, String userCode, Long startTime, Long endTime) {
        Machine machine = purviewCheckUserCode(loginInfo, userCode);
        return getByMachineNOAndTime(mapType, machine.getMachineNO(), startTime, endTime,machine.getMachineId());
    }

    @Override
    public Integer getMileageByMachineNoAndTime(LoginInfo loginInfo, String userCode, Long startTime, Long endTime) {
        Machine machine = purviewCheckUserCode(loginInfo, userCode);

        Map<String, Object> params = new HashMap<>(8);
        params.put("machineNO", machine.getMachineNO());
        params.put("startTime", new Date(startTime));
        params.put("endTime", new Date(endTime));

        return historyDao.getMileageByMachineNOAndTime(params);
    }

    @Override
    public Double getMileageByMachineNoAndTime(String machineNo, Long startTime, Long endTime) {
        Map<String, Object> params = new HashMap<>(8);
        params.put("machineNO", machineNo);
        params.put("startTime", new Date(startTime));
        params.put("endTime", new Date(endTime));
        return Optional.ofNullable(historyDao.getMileageByMachineNOAndTime(params))
                .map(x -> x / 1000d)
                .map(x -> new DecimalFormat("#.00").format(x))
                .map(Double::parseDouble)
                .orElse(0.0D);
    }

    @Override
    public List<TerPosition> getLastRideHistory(LoginInfo loginInfo, Integer mapType, String userCode) {
        Machine machine = purviewCheckUserCode(loginInfo, userCode);

        /**查询设备最后一次骑行轨迹*/
        RideLog rideLog = rideLogDao.findLastByMachineId(machine.getMachineId());

        if (rideLog == null) {
            return getByMachineNO(mapType, machine.getMachineNO());
        } else {
            Date startTime = rideLog.getStartTime();
            Date endTime = new Date();

            /**判断设备是否正在骑行*/
            MachineBorrow machineBorrow = machineBorrowDao.getByMachineId(machine.getMachineId());
            if (machineBorrow == null) {
                endTime = rideLog.getEndTime();
            }

            return getByMachineNOAndTime(mapType, machine.getMachineNO(), startTime.getTime(), endTime.getTime(),machine.getMachineId());
        }
    }

    @Override
    public List<TerPosition> getLastActiveHistory(LoginInfo loginInfo, Integer mapType, String userCode) {
        Machine machine = purviewCheckUserCode(loginInfo, userCode);

        /**查询设备最后一次骑行轨迹*/
        RideLog rideLog = rideLogDao.findLastByMachineId(machine.getMachineId());

        if (rideLog == null) {
            return getByMachineNO(mapType, machine.getMachineNO());
        } else {

            /**判断设备是否正在骑行*/
            MachineBorrow machineBorrow = machineBorrowDao.getByMachineId(machine.getMachineId());
            if (machineBorrow != null) {
                return new ArrayList<>();
            }
            Date startTime = rideLog.getEndTime();
            Date endTime = new Date();
            return getByMachineNOAndTime(mapType, machine.getMachineNO(), startTime.getTime(), endTime.getTime(),machine.getMachineId());
        }
    }

    @Override
    public List<TerPosition> getByMachineNO(Integer mapType, String machineNO) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("machineNO", machineNO);
        List<TerPosition> history = historyDao.getByMachineNO(params);

        CalibrateUtils.calibrateObjects(calibrateService, history, mapType);

        return history;
    }

    /**
     * 根据设备编号批量查询
     *
     * @param mapType
     * @param accountUserPhone
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public List<TerPosition> getByAccountUserPhoneAndTime(Integer mapType, String accountUserPhone, String startTime, String endTime) {
        /*Map<String, Object> params = new HashMap<String, Object>();
        params.put("accountUserPhone", accountUserId);
        params.put("startTime", startTime);
        params.put("endTime", endTime);*/
        //获取查询的时间分段参数
        List<Map<String, Object>> searchParams = this.getSearchParams(accountUserPhone, startTime, endTime,"accountUserPhone",true);
        List<TerPosition> historyList = new ArrayList<>();
        for (Map<String, Object> param : searchParams) {
            List<TerPosition> history = historyDao.getByAccountUserPhoneAndTime(param);
            if (history.size() > 0) {
                calibrateService.calibrateOffSet(history, mapType);
                historyList.addAll(history);
            }
        }
        return historyList;
    }

    /**
     * @description: 根据时间范围返回分段查询参数
     * @author: mo.shanyong
     * @date: 2025/4/21 10:27
     * @param: machineNO 设别编号
     * @param: startTime 开始时间
     * @param: endTime 结束时间
     * @param: paramName 查询的参数名
     * @param: checkCount 是否检查数据量
     * @return: java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     */
    @Override
    public List<Map<String, Object>> getSearchParams(String machineNO,String start,String end,String paramName,boolean checkCount) {
        List<Map<String, Object>> searchParamList = new ArrayList<>();
        LocalDateTime startDateTime = DateTimeUtil.getLocalDateTimeByTimeStr(start);
        LocalDateTime endDateTime = DateTimeUtil.getLocalDateTimeByTimeStr(end);
        long betweenHours = ChronoUnit.HOURS.between(startDateTime, endDateTime);
        Map<String, Object> params = new HashMap<>();
        params.put(paramName, machineNO);
        params.put("startTime", DateTimeUtil.getDateByDateStr(start));
        params.put("endTime", DateTimeUtil.getDateByDateStr(end));
        if (betweenHours < 8L){
            searchParamList.add(params);
            return searchParamList;
        }
        if (checkCount) {
            int count = historyDao.getCountByMachineNOAndTime(params);
            if (count <= 5000) {
                searchParamList.add(params);
                return searchParamList;
            }
        }
        do {
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put(paramName, machineNO);
            paramMap.put("startTime", Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant()));
            LocalDateTime localDateTime = startDateTime.plusHours(8).isAfter(endDateTime) ? endDateTime : startDateTime.plusHours(8);
            paramMap.put("endTime", Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()));
            searchParamList.add(paramMap);
            if (localDateTime.isAfter(endDateTime) || localDateTime.isEqual(endDateTime)){
                break;
            }
            startDateTime = localDateTime.plusSeconds(1);
        }while (true);
        return searchParamList;
    }

    /**
     * @description: 获取车辆各个轨迹点的电量
     * @author: mo.shanyong
     * @date: 2025/4/21 14:49
     * @param: historyList
     * @param: machineId
     */
    private void getMachineSoc(List<TerPosition> historyList,Integer machineId){
        if (CollectionUtils.isEmpty(historyList)){
            return;
        }
        List<BatteryModelDetail> batteryModelDetails = batteryModelDetailService.getByMachineId(machineId);
        for (TerPosition terPosition : historyList) {
            if (terPosition.getCartV() <= 0){
                terPosition.setSoc(0);
                continue;
            }
            double cartV = terPosition.getCartV();
            if (CollectionUtils.isEmpty(batteryModelDetails)){
                terPosition.setSoc(0);
                continue;
            }
            for (BatteryModelDetail batteryModelDetail : batteryModelDetails) {
                if (batteryModelDetail.getMinVol() <= cartV && cartV <= batteryModelDetail.getMaxVol()) {
                    terPosition.setSoc(batteryModelDetail.getBatteryPer());
                    break;
                }
            }

        }

    }
}